<template>
  <view
      v-if="show"
      :class="[vertical && 'u-loading-icon--vertical']"
      :style="[$u.addStyle(customStyle)]"
      class="u-loading-icon"
  >
    <view
        v-if="!webviewHide"
        ref="ani"
        :class="[`u-loading-icon__spinner--${mode}`]"
        :style="{
				color: color,
				width: $u.addUnit(size),
				height: $u.addUnit(size),
				borderTopColor: color,
				borderBottomColor: otherBorderColor,
				borderLeftColor: otherBorderColor,
				borderRightColor: otherBorderColor,
				'animation-duration': `${duration}ms`,
				'animation-timing-function': mode === 'semicircle' || mode === 'circle' ? timingFunction : ''
			}"
        class="u-loading-icon__spinner"
    >
      <block v-if="mode === 'spinner'">
        <!-- #ifndef APP-NVUE -->
        <view
            v-for="(item, index) in array12"
            :key="index"
            class="u-loading-icon__dot"
        >
        </view>
        <!-- #endif -->
        <!-- #ifdef APP-NVUE -->
        <!-- 此组件内部图标部分无法设置宽高，即使通过width和height配置了也无效 -->
        <loading-indicator
            v-if="!webviewHide"
            :animating="true"
            :style="{
						color: color,
						width: $u.addUnit(size),
						height: $u.addUnit(size)
					}"
            class="u-loading-indicator"
        />
        <!-- #endif -->
      </block>
    </view>
    <text
        v-if="text"
        :style="{
				fontSize: $u.addUnit(textSize),
				color: textColor,
			}"
        class="u-loading-icon__text"
    >{{ text }}
    </text>
  </view>
</template>

<script>
import props from './props.js';
// #ifdef APP-NVUE
const animation = weex.requireModule('animation');
// #endif
/**
 * loading 加载动画
 * @description 警此组件为一个小动画，目前用在uView的loadmore加载更多和switch开关等组件的正在加载状态场景。
 * @tutorial https://www.uviewui.com/components/loading.html
 * @property {Boolean}      show      是否显示组件  (默认 true)
 * @property {String}      color      动画活动区域的颜色，只对 mode = flower 模式有效（默认color['u-tips-color']）
 * @property {String}      textColor    提示文本的颜色（默认color['u-tips-color']）
 * @property {Boolean}      vertical    文字和图标是否垂直排列 (默认 false )
 * @property {String}      mode      模式选择，见官网说明（默认 'circle' ）
 * @property {String | Number}  size      加载图标的大小，单位px （默认 24 ）
 * @property {String | Number}  textSize    文字大小（默认 15 ）
 * @property {String | Number}  text      文字内容
 * @property {String}      timingFunction  动画模式 （默认 'ease-in-out' ）
 * @property {String | Number}  duration    动画执行周期时间（默认 1200）
 * @property {String}      inactiveColor  mode=circle时的暗边颜色
 * @property {Object}      customStyle    定义需要用到的外部样式
 * @example <u-loading mode="circle"></u-loading>
 */
export default {
  name: 'u-loading-icon',
  mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
  data() {
    return {
      // Array.form可以通过一个伪数组对象创建指定长度的数组
      // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/from
      array12: Array.from({
        length: 12
      }),
      // 这里需要设置默认值为360，否则在安卓nvue上，会延迟一个duration周期后才执行
      // 在iOS nvue上，则会一开始默认执行两个周期的动画
      aniAngel: 360, // 动画旋转角度
      webviewHide: false, // 监听webview的状态，如果隐藏了页面，则停止动画，以免性能消耗
      loading: false, // 是否运行中，针对nvue使用
    }
  },
  computed: {
    // 当为circle类型时，给其另外三边设置一个更轻一些的颜色
    // 之所以需要这么做的原因是，比如父组件传了color为红色，那么需要另外的三个边为浅红色
    // 而不能是固定的某一个其他颜色(因为这个固定的颜色可能浅蓝，导致效果没有那么细腻良好)
    otherBorderColor() {
      const lightColor = uni.$u.colorGradient(this.color, '#ffffff', 100)[80]
      if (this.mode === 'circle') {
        return this.inactiveColor ? this.inactiveColor : lightColor
      } else {
        return 'transparent'
      }
      // return this.mode === 'circle' ? this.inactiveColor ? this.inactiveColor : lightColor : 'transparent'
    }
  },
  watch: {
    show(n) {
      // nvue中，show为true，且为非loading状态，就重新执行动画模块
      // #ifdef APP-NVUE
      if (n && !this.loading) {
        setTimeout(() => {
          this.startAnimate()
        }, 30)
      }
      // #endif
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    init() {
      setTimeout(() => {
        // #ifdef APP-NVUE
        this.show && this.nvueAnimate()
        // #endif
        // #ifdef APP-PLUS
        this.show && this.addEventListenerToWebview()
        // #endif
      }, 20)
    },
    // 监听webview的显示与隐藏
    addEventListenerToWebview() {
      // webview的堆栈
      const pages = getCurrentPages()
      // 当前页面
      const page = pages[pages.length - 1]
      // 当前页面的webview实例
      const currentWebview = page.$getAppWebview()
      // 监听webview的显示与隐藏，从而停止或者开始动画(为了性能)
      currentWebview.addEventListener('hide', () => {
        this.webviewHide = true
      })
      currentWebview.addEventListener('show', () => {
        this.webviewHide = false
      })
    },
    // #ifdef APP-NVUE
    nvueAnimate() {
      // nvue下，非spinner类型时才需要旋转，因为nvue的spinner类型，使用了weex的
      // loading-indicator组件，自带旋转功能
      this.mode !== 'spinner' && this.startAnimate()
    },
    // 执行nvue的animate模块动画
    startAnimate() {
      this.loading = true
      const ani = this.$refs.ani
      if (!ani) return
      animation.transition(ani, {
        // 进行角度旋转
        styles: {
          transform: `rotate(${this.aniAngel}deg)`,
          transformOrigin: 'center center'
        },
        duration: this.duration,
        timingFunction: this.timingFunction,
        // delay: 10
      }, () => {
        // 每次增加360deg，为了让其重新旋转一周
        this.aniAngel += 360
        // 动画结束后，继续循环执行动画，需要同时判断webviewHide变量
        // nvue安卓，页面隐藏后依然会继续执行startAnimate方法
        this.show && !this.webviewHide ? this.startAnimate() : this.loading = false
      })
    }
    // #endif
  }
}
</script>

<style lang="scss" scoped>
@import "../../libs/css/components.scss";

$u-loading-icon-color: #c8c9cc !default;
$u-loading-icon-text-margin-left:4px !default;
$u-loading-icon-text-color:$u-content-color !default;
$u-loading-icon-text-font-size:14px !default;
$u-loading-icon-text-line-height:20px !default;
$u-loading-width:30px !default;
$u-loading-height:30px !default;
$u-loading-max-width:100% !default;
$u-loading-max-height:100% !default;
$u-loading-semicircle-border-width: 2px !default;
$u-loading-semicircle-border-color:transparent !default;
$u-loading-semicircle-border-top-right-radius: 100px !default;
$u-loading-semicircle-border-top-left-radius: 100px !default;
$u-loading-semicircle-border-bottom-left-radius: 100px !default;
$u-loading-semicircle-border-bottom-right-radiu: 100px !default;
$u-loading-semicircle-border-style: solid !default;
$u-loading-circle-border-top-right-radius: 100px !default;
$u-loading-circle-border-top-left-radius: 100px !default;
$u-loading-circle-border-bottom-left-radius: 100px !default;
$u-loading-circle-border-bottom-right-radiu: 100px !default;
$u-loading-circle-border-width:2px !default;
$u-loading-circle-border-top-color:#e5e5e5 !default;
$u-loading-circle-border-right-color:$u-loading-circle-border-top-color !default;
$u-loading-circle-border-bottom-color:$u-loading-circle-border-top-color !default;
$u-loading-circle-border-left-color:$u-loading-circle-border-top-color !default;
$u-loading-circle-border-style:solid !default;
$u-loading-icon-host-font-size:0px !default;
$u-loading-icon-host-line-height:1 !default;
$u-loading-icon-vertical-margin:6px 0 0 !default;
$u-loading-icon-dot-top:0 !default;
$u-loading-icon-dot-left:0 !default;
$u-loading-icon-dot-width:100% !default;
$u-loading-icon-dot-height:100% !default;
$u-loading-icon-dot-before-width:2px !default;
$u-loading-icon-dot-before-height:25% !default;
$u-loading-icon-dot-before-margin:0 auto !default;
$u-loading-icon-dot-before-background-color:currentColor !default;
$u-loading-icon-dot-before-border-radius:40% !default;

.u-loading-icon {
  /* #ifndef APP-NVUE */
  // display: inline-flex;
  /* #endif */
  flex-direction: row;
  align-items: center;
  justify-content: center;
  color: $u-loading-icon-color;

  &__text {
    margin-left: $u-loading-icon-text-margin-left;
    color: $u-loading-icon-text-color;
    font-size: $u-loading-icon-text-font-size;
    line-height: $u-loading-icon-text-line-height;
  }

  &__spinner {
    width: $u-loading-width;
    height: $u-loading-height;
    position: relative;
    /* #ifndef APP-NVUE */
    box-sizing: border-box;
    max-width: $u-loading-max-width;
    max-height: $u-loading-max-height;
    animation: u-rotate 1s linear infinite;
    /* #endif */
  }

  &__spinner--semicircle {
    border-width: $u-loading-semicircle-border-width;
    border-color: $u-loading-semicircle-border-color;
    border-top-right-radius: $u-loading-semicircle-border-top-right-radius;
    border-top-left-radius: $u-loading-semicircle-border-top-left-radius;
    border-bottom-left-radius: $u-loading-semicircle-border-bottom-left-radius;
    border-bottom-right-radius: $u-loading-semicircle-border-bottom-right-radiu;
    border-style: $u-loading-semicircle-border-style;
  }

  &__spinner--circle {
    border-top-right-radius: $u-loading-circle-border-top-right-radius;
    border-top-left-radius: $u-loading-circle-border-top-left-radius;
    border-bottom-left-radius: $u-loading-circle-border-bottom-left-radius;
    border-bottom-right-radius: $u-loading-circle-border-bottom-right-radiu;
    border-width: $u-loading-circle-border-width;
    border-top-color: $u-loading-circle-border-top-color;
    border-right-color: $u-loading-circle-border-right-color;
    border-bottom-color: $u-loading-circle-border-bottom-color;
    border-left-color: $u-loading-circle-border-left-color;
    border-style: $u-loading-circle-border-style;
  }

  &--vertical {
    flex-direction: column
  }
}

/* #ifndef APP-NVUE */
:host {
  font-size: $u-loading-icon-host-font-size;
  line-height: $u-loading-icon-host-line-height;
}

.u-loading-icon {
  &__spinner--spinner {
    animation-timing-function: steps(12)
  }

  &__text:empty {
    display: none
  }

  &--vertical &__text {
    margin: $u-loading-icon-vertical-margin;
    color: $u-content-color;
  }

  &__dot {
    position: absolute;
    top: $u-loading-icon-dot-top;
    left: $u-loading-icon-dot-left;
    width: $u-loading-icon-dot-width;
    height: $u-loading-icon-dot-height;

    &:before {
      display: block;
      width: $u-loading-icon-dot-before-width;
      height: $u-loading-icon-dot-before-height;
      margin: $u-loading-icon-dot-before-margin;
      background-color: $u-loading-icon-dot-before-background-color;
      border-radius: $u-loading-icon-dot-before-border-radius;
      content: " "
    }
  }
}

@for $i from 1 through 12 {
  .u-loading-icon__dot:nth-of-type(#{$i}) {
    transform: rotate($i *30deg);
    opacity: 1 -0.0625 *($i -1);
  }
}

@keyframes u-rotate {
  0% {
    transform: rotate(0deg)
  }

  to {
    transform: rotate(1turn)
  }
}

/* #endif */
</style>
